package com.uum.admin.controller;


import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nimbusds.jwt.JWT;
import com.uum.admin.pojo.entity.*;
import com.uum.admin.pojo.form.PermissionRoleForm;
import com.uum.admin.pojo.query.RolePageQuery;
import com.uum.admin.service.*;
import com.uum.common.core.annotation.Operation;
import com.uum.common.core.constant.GlobalConstants;
import com.uum.common.core.enums.BusinessType;
import com.uum.common.core.result.Result;
import com.uum.web.exception.BizException;
import com.uum.web.util.JwtUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.websocket.OnError;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Api(tags = "角色接口")
@RestController
@RequestMapping("/api/v1/role")
@RequiredArgsConstructor
public class SysRoleController {

    private final SysRoleService sysRoleService;
    private final SysPermissionService sysPermissionService;
    private final SysMenuRoleService sysMenuRoleService;
    private final SysPermissionRoleService sysPermissionRoleService;
    private final SysUserRoleService sysUserRoleService;

    @Operation(description = "查询角色列表",businessType = BusinessType.QUERY,isSaveResponseData = false)
    @ApiOperation(value = "角色列表分页")
    @GetMapping("/page")
    public Result getRolePageList(RolePageQuery rolePageQuery) {
        // 判断是否是超级管理员
        Boolean isRoot = JwtUtils.isAdministrator();
        String name = rolePageQuery.getName();
        List<String> roles = JwtUtils.getRoles();
        List<String> roleList = roles.stream().filter(item -> !item.equals(GlobalConstants.SUPER_ROLE_CODE)).collect(Collectors.toList());
        IPage<SysRole> result = sysRoleService.page(new Page<>(rolePageQuery.getCurrentPage(), rolePageQuery.getPageSize()),
                new LambdaQueryWrapper<SysRole>()
                        .eq(!isRoot, SysRole::getCreateUserId, JwtUtils.getUserId())
                        .or()
                        .in(!isRoot,SysRole::getCode,roleList)
                        .like(StrUtil.isNotBlank(name), SysRole::getName, name));
        return Result.success(result);
    }


    @ApiOperation("角色列表(下拉选择器)")
    @GetMapping("select")
    public Result listRole() {
        Boolean isRoot = JwtUtils.isAdministrator();
        if (isRoot) {
            //超级管理员查所有
            List<SysRole> result = sysRoleService.list();
            return Result.success(result);
        } else {
            //查询该角色下创建的角色以及自身
            List<String> roles = JwtUtils.getRoles();
            List<SysRole> result = sysRoleService.list(new LambdaQueryWrapper<SysRole>()
                    .eq(SysRole::getCreateUserId, JwtUtils.getUserId())
                    .or()
                    .in(SysRole::getCode,roles));
            return Result.success(result);
        }
    }

    @ApiOperation("角色详情")
    @GetMapping("detail/{id}")
    public Result roleDetail(@PathVariable Long id) {
        SysRole role = sysRoleService.getById(id);
        return Result.success(role);
    }

    @Operation(description = "新增角色",businessType = BusinessType.INSERT)
    @ApiOperation("保存角色")
    @PostMapping("add")
    public Result saveRole(@RequestBody SysRole role) {
        role.setCreateUserId(JwtUtils.getUserId());
        boolean result = sysRoleService.save(role);
        return Result.judge(result);
    }

    @Operation(description = "修改角色",businessType = BusinessType.UPDATE)
    @ApiOperation("修改角色")
    @PutMapping("update")
    public Result updateRole(@RequestBody SysRole role) {
        String code = sysRoleService.getById(role.getRoleId()).getCode();
        valid(code);
        boolean result = sysRoleService.updateById(role);
        //修改角色编码时 需要重置redis的角色-权限
        if (result && !code.equals(role.getCode())) {
            sysPermissionService.refreshPermRolesRules();
        }
        return Result.judge(result);
    }

    @Operation(description = "删除角色",businessType = BusinessType.DELETE)
    @ApiOperation("删除角色")
    @DeleteMapping("delete/{id}")
    @Transactional
    public Result deleteRole(@PathVariable String id) {
        String code = sysRoleService.getById(id).getCode();
        valid(code);
        //删除角色时
        boolean result = sysRoleService.removeById(id);
        //删除菜单角色
        sysMenuRoleService.remove(new LambdaQueryWrapper<SysMenuRole>().eq(SysMenuRole::getRoleId, id));
        //删除权限角色
        sysPermissionRoleService.remove(new LambdaQueryWrapper<SysPermissionRole>().eq(SysPermissionRole::getRoleId, id));
        //删除用户角色
        sysUserRoleService.remove(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId, id));
        if (result) {
            sysPermissionService.refreshPermRolesRules();
        }
        return Result.success();
    }

    @ApiOperation(value = "角色的菜单列表")
    @GetMapping("listByRole/{roleId}")
    public Result listMenuByRoleId(@PathVariable String roleId) {
        List<Long> menuIdList = sysMenuRoleService
                .list(new LambdaQueryWrapper<SysMenuRole>().eq(SysMenuRole::getRoleId, roleId).select(SysMenuRole::getMenuId))
                .stream().map(SysMenuRole::getMenuId).collect(Collectors.toList());
        return Result.success(menuIdList);
    }

    @Operation(description = "修改角色的菜单",businessType = BusinessType.UPDATE)
    @ApiOperation(value = "修改角色菜单")
    @PutMapping(value = "/{roleId}/menu")
    @Transactional
    public Result updateRoleMenu(@ApiParam("角色ID") @PathVariable Long roleId, @RequestBody SysRole role) {
        validById(roleId);
        List<Long> menuIds = role.getMenuIdList();
        sysMenuRoleService.remove(new LambdaQueryWrapper<SysMenuRole>().eq(SysMenuRole::getRoleId, roleId));
        if (!menuIds.isEmpty()) {
            List<SysMenuRole> menuRoleList = new ArrayList<>(menuIds.size());
            for (Long menuId : menuIds) {
                SysMenuRole sysMenuRole = new SysMenuRole().setMenuId(menuId).setRoleId(roleId);
                menuRoleList.add(sysMenuRole);
            }
            sysMenuRoleService.saveBatch(menuRoleList);
        }
        sysPermissionService.refreshPermRolesRules();
        return Result.success();
    }

    @ApiOperation(value = "角色的权限列表")
    @GetMapping("/{roleId}/permissions")
    public Result listRolePermission(@ApiParam("角色ID") @PathVariable Long roleId, @ApiParam("菜单ID") Long menuId) {
        List<Long> result = sysPermissionRoleService.listPermIds(menuId, roleId);
        return Result.success(result);
    }

    @Operation(description = "修改角色权限",businessType = BusinessType.UPDATE)
    @ApiOperation(value = "修改角色权限")
    @PutMapping(value = "/{roleId}/permissions")
    public Result updateRolePerms(
            @ApiParam("角色ID") @PathVariable Long roleId, @RequestBody PermissionRoleForm rolePerms) {
        validById(roleId);
        rolePerms.setRoleId(roleId);
        sysPermissionRoleService.saveRolePerms(rolePerms);
        sysPermissionService.refreshPermRolesRules();
        return Result.success();
    }

    private void validById(Long roleId) {
        String code = sysRoleService.getById(roleId).getCode();
        valid(code);
    }


    /**
     * 校验是否越权
     * @param code 修改的角色
     */
    private void valid(String code) {
        if (JwtUtils.isAdministrator()) {
            return;
        }
        //自身的角色
        List<String> roles = JwtUtils.getRoles();
        if (roles.contains(code)) {
            throw new BizException("不能修改自身角色或权限，请联系上级");
        }

        //修改的角色是否自身创建的
        List<String> codeList = sysRoleService.list(new LambdaQueryWrapper<SysRole>().eq(SysRole::getCreateUserId, JwtUtils.getUserId()).select(SysRole::getCode)).stream().map(SysRole::getCode).collect(Collectors.toList());
        if (!codeList.contains(code)) {
            throw new BizException("不能越权修改角色或权限");
        }
    }

}

